local Constants = require ("scripts.constants")
local TimerManger = require ("scripts.TimerManager")
local Block = require ("view.block")
local Window = {
	new = function()
		local self = {}
		self.blocks = {}
		self.topRow = Constants.NUMBER_ROWS

		self.printTable = function()
			local blocks = self.blocks
			print("----------------------------------------------------------")
			for row = 1, Constants.NUMBER_ROWS do
				io.write("[")
				if(blocks[row] ~= nil) then
					local currentRow = blocks[row]
					for column = 1, Constants.NUMBER_BLOCKS do
						if(currentRow[column] ~= nil) then
							io.write(currentRow[column].fillName, "\t")
						else
							io.write("X", "\t")
						end
					end
				else
					for column = 1, Constants.NUMBER_BLOCKS do io.write("X", "\t") end
				end
				io.write("]\n\r")
			end
			print("----------------------------------------------------------")
		end

		self.createRow = function()
			if(self.topRow > 0) then
				local blocks = self.blocks;
				if(self.topRow ~= Constants.NUMBER_ROWS) then
					for index = self.topRow + 1, Constants.NUMBER_ROWS do
						if(blocks[index] ~= nil) then
							blocks[index - 1] = {}
							for blockIndex = 1, Constants.NUMBER_BLOCKS do
								local block = blocks[index][blockIndex]
								if(block ~= nil) then
									block.windowPosition.row = index - 1
									block.displayObject.y = block.displayObject.y - Constants.BLOCK_HEIGHT
									blocks[index - 1][blockIndex] = block
								end
							end
						end
					end
				end
				local row = Constants.NUMBER_ROWS
				blocks[row] = nil
				blocks[row] = {}
				for index = 1, Constants.NUMBER_BLOCKS, 1 do
					local block = Block.new(row, index)
					local notSupportedFill = {}
					if(blocks[row - 1] ~= nil and blocks[row - 1][index] ~= nil) then
						notSupportedFill[blocks[row - 1][index].fillName] = true
					end
					if(blocks[row] ~= nil and blocks[row][index - 1] ~= nil) then
						notSupportedFill[blocks[row][index - 1].fillName] = true
					end
					block.setFill(notSupportedFill)
					table.insert(blocks[row], block)
				end
				self.topRow = self.topRow - 1
			end
		end

		self.init = function()
			local width = Constants.BLOCK_WIDTH * Constants.NUMBER_BLOCKS
			local height = Constants.BLOCK_HEIGHT * Constants.NUMBER_ROWS
			local offsetX = (display.contentWidth - width) / 2
			local offsetY = (display.contentHeight - height) / 2
			local background = display.newRect(offsetX, offsetY, width, height)
			background:setStrokeColor(200, 200, 200)
			background.strokeWidth = 1
			self.background = background
			self.top = offsetY
			self.bottom = offsetY + height - Constants.BLOCK_HEIGHT
			self.left = offsetX
			self.right = offsetX + width
			self.topRow = Constants.NUMBER_ROWS
			self.createRow()
			
			self.target = display.newImage("images/target_32.png")
			self.target.x = offsetX
			self.target.y = offsetY
		end

		self.restoreBlocks = function()
			local blocks = self.blocks
			for index = 1, Constants.NUMBER_ROWS do
				local row = blocks[index]
				if(row ~= nil) then
					for rowIndex = 1, Constants.NUMBER_BLOCKS do
						local block = row[rowIndex]
						if(block ~= nil) then
							block.markForRemove = false
						end
					end
				end
			end
		end

		self.remove = function(blocks, blocksToRemove)
			for index = 1, #blocksToRemove do
				local block = blocksToRemove[index]
				if(block ~= nil and block.displayObject ~= nil) then
					local windowPosition = block.windowPosition
					block.displayObject:removeSelf()
					block.displayObject = nil
					block = nil
					blocks[windowPosition.row][windowPosition.column] = nil
				end
			end
		end

		self.searchRightLeft = function(blocks, fillName, blocksToRemove, row, start, limit, step)
			for index = start, limit, step do
				if(blocks[row][index] ~= nil and blocks[row][index].fillName == fillName) then
					table.insert(blocksToRemove, blocks[row][index])
				else
					return index + -1 * step
				end
			end
			return limit
		end

		self.searchUpDown = function(blocks, fillName, blocksToRemove, column, start, limit, step)
			for index = start, limit, step do
				if(blocks[index][column] ~= nil and blocks[index][column].fillName == fillName) then
					table.insert(blocksToRemove, blocks[index][column])
				else
					return index + -1 * step
				end
			end
			return limit
		end

		self.dropColumnAfterRemoving = function(blocks, minRow, maxRow, column, totalRows)
			if(minRow - 1 > 0) then
				local block = blocks[minRow - 1][column]
				while blocks[minRow - 1] ~= nil and blocks[minRow - 1][column] ~= nil do
					block = blocks[minRow - 1][column]
					transition.to(block.displayObject, {y = block.displayObject.y + (Constants.BLOCK_HEIGHT * totalRows), time = 500})
					block.windowPosition.row = block.windowPosition.row + totalRows
					blocks[maxRow][column] = block
					blocks[minRow - 1][column] = nil
					minRow = minRow - 1
					maxRow = maxRow - 1
					if(minRow < 1) then break end
				end
			end
		end

		self.dropRowAfterRemoving = function(blocks, currentColumn, row, minColumn, maxColumn)
			for index = minColumn, maxColumn do
				if(index ~= currentColumn) then
					self.dropColumnAfterRemoving(blocks, row, row, index, 1)
				end
			end
		end

		self.removeMatching = function(currentBlock)
			local fillName = currentBlock.fillName
			local position = currentBlock.windowPosition
			local blocks = self.blocks
			local blocksToRemove = {}
			local dropInColumn, dropInRow = false, false
			local maxColumn = self.searchRightLeft(blocks, fillName, blocksToRemove, position.row, position.column + 1, Constants.NUMBER_BLOCKS, 1)
			local minColumn = self.searchRightLeft(blocks, fillName, blocksToRemove, position.row, position.column - 1, 1, -1)
			if(#blocksToRemove >= 2) then
				self.remove(blocks, blocksToRemove)
				dropInRow = true
			end
			blocksToRemove = nil
			blocksToRemove = {}
			local maxRow = self.searchUpDown(blocks, fillName, blocksToRemove, position.column, position.row, Constants.NUMBER_ROWS, 1)
			local minRow = self.searchUpDown(blocks, fillName, blocksToRemove, position.column, position.row -1, 1, -1)
			if(#blocksToRemove >= 3) then
				self.remove(blocks, blocksToRemove)
				dropInColumn = true
			elseif(dropInRow) then
				self.remove(blocks, {currentBlock})
			end
			blocksToRemove = nil
			blocksToRemove = {}
			if(dropInColumn and dropInRow) then
				self.dropRowAfterRemoving(blocks, position.column, position.row, minColumn, maxColumn)
				self.dropColumnAfterRemoving(blocks, minRow, maxRow, position.column, maxRow - minRow + 1)
			elseif(dropInRow) then
				self.dropRowAfterRemoving(blocks, -1, position.row, minColumn, maxColumn)
			elseif(dropInColumn) then
				self.dropColumnAfterRemoving(blocks, minRow, maxRow, position.column, maxRow - minRow + 1)
			end
		end

		self.dropFloatBlocks = function(currentBlock, direction)
			if(currentBlock ~= nil) then
				local blocks = self.blocks
				local position = currentBlock.windowPosition
				local row = currentBlock.windowPosition.row
				local column = currentBlock.windowPosition.column
				self.dropRowAfterRemoving(blocks, -1, position.row, column - direction, column - direction)
				if(row + 1 <= Constants.NUMBER_ROWS) then
					while blocks[row + 1] == nil or blocks[row + 1][column] == nil do
						if(row + 1 > Constants.NUMBER_ROWS) then break end
						row = row + 1
					end
					if(blocks[row] == nil) then blocks[row] = {} end
					blocks[currentBlock.windowPosition.row][currentBlock.windowPosition.column] = nil
					currentBlock.windowPosition.row = row
					transition.to(currentBlock.displayObject, {y = (self.top + (row - 1) * Constants.BLOCK_HEIGHT) + Constants.BLOCK_HEIGHT / 2, time = 500})
					blocks[row][column] = currentBlock
				end
			end
		end

		self.switchBlocks = function(x, y, direction)
			local column = math.floor((x - self.left) / Constants.BLOCK_WIDTH) + 1
			local row = math.floor((y - self.top) / Constants.BLOCK_HEIGHT) + 1
			local blocks = self.blocks[row]
			if(blocks ~= nil and blocks[column] ~= nil and blocks[column + direction] ~= nil) then
				local leftBlock, rightBlock = blocks[column], blocks[column + direction]
				leftBlock, rightBlock = rightBlock, leftBlock
				transition.to(leftBlock.displayObject, {x = rightBlock.displayObject.x, time = 150})
				transition.to(rightBlock.displayObject, {x = leftBlock.displayObject.x, time = 150, onComplete = function()
						leftBlock.windowPosition, rightBlock.windowPosition = rightBlock.windowPosition, leftBlock.windowPosition
						blocks[column], blocks[column + direction] = leftBlock, rightBlock
						self.removeMatching(rightBlock)
						self.removeMatching(leftBlock)
		--					self.printTable()
					end})
			elseif(blocks ~= nil and blocks[column] ~= nil) then
				local leftBlock = blocks[column]
				transition.to(leftBlock.displayObject, {x = leftBlock.displayObject.x + direction * Constants.BLOCK_WIDTH, time = 150, onComplete = 
						function()
							leftBlock.windowPosition.column = leftBlock.windowPosition.column + direction
							blocks[column] = nil
							blocks[column + direction] = leftBlock
							self.removeMatching(leftBlock)
							self.dropFloatBlocks(leftBlock, direction)
			--					self.printTable()
						end
					}
				)
			end
		end

		self.touch = function(event)
			local direction = 0
			self.target.x = event.x
			self.target.y = event.y
			self.target:toFront()
			if(event.phase == "began") then
				self.startX = event.x
				self.startY = event.y
			elseif(event.phase == "moved") then
				if(event.x == self.startX) then
					return
				end
				if(event.x > self.startX) then
					self.direction = 1
				else
					self.direction = -1
				end
			else
				if(event.x == self.startX) then
					return
				end
				self.switchBlocks(self.startX, self.startY, self.direction)
			end
--			if(event.phase == "began") then
--				self.switchBlocks(event.x, event.y, 1)
--			end
		end

		self.init()

		self.background:addEventListener("touch", self.touch)
		timer.performWithDelay(10, self.createRow, 0)
		return self
	end
}
return Window